/**
 * 发布订阅模式：一对多的依赖关系，使得每当一个对象改变状态，则所有依赖于它的对象都会得到通知并被自动更新。 ——发布订阅模式
 * 事件总线是对发布-订阅模式的一种实现
 * 订阅on
 * 取消订阅 off
 * 发布 emit(name,once=[true|false],fn); 执行name注册的所有事件
 */
class EventEmitter {
  constructor(){
    //创建一个数据源
    this.cache = {}
  }
  on(name, fn){
    if(!this.cache[name]) {
      this.cache[name] = []
    }
    this.cache[name].push(fn)
  }
  off(name, fn){
    if(!name) {
      this.cache = {}
      return
    }
    if(!fn) {
      delete this.cache[name]
      return
    }
    const listeners = this.cache[name];
    if(listeners) {
      this.cache[name] = listeners.filter(f => f!==fn)
    }
  }
  emit(name, once=false, ...args){
    if(this.cache[name]) {
      this.cache[name].forEach(fn => {
        fn(...args)
      })
      once && this.off(name)
    }
  }
}

/**
 * vue2风格的eventBus
 */
class EventBus{
  constructor() {
    this.event = {}
  }
  $on(name, callback) {
    if(!this.event[name]) {
      this.event[name] = []
    }
    this.event[name].push(callback)
  }
  $emit(name, ...args) {
    if(this.event[name]) {
      this.event[name].forEach(fn => {
        fn(...args)
      })
    }
  }
  $off(name,callback) {
    if(!name) {
      this.event = {}
      return
    }
    if(!callback) {
      delete this.event[name]
      return
    }
    const listeners = this.event[name];
    if(listeners) {
      this.event[name] = listeners.filter(fn => fn !== callback)
    }
  }
  $once(name, ...args) {
    if(this.event[name]) {
      this.event[name].forEach(fn => {
        fn(...args)
      })
      this.$off(name)
    }
  }
}
// 测试
const bus = new EventBus();
bus.$on('test1', (...args) => {
  console.log('i am test1,and the params is ', ...args)
})
bus.$once('test1',1,2,3)
bus.$emit('test1',1,11)
/**
 * vue3风格的eventBus
 */
import { reactive, toRefs } from 'vue'
const eventbus = reactive({
  events: {},
  on(name, callback) {
    if(!this.events[name]) {
      this.events[name] = []
    }
    this.event[name].push(callback);
    //this.event[name] = [].concat(this.event[name]||[], callback)
  },
  emit(name, ...args) {
    if(this.events[name]) {
      this.events[name].forEach(fn => {
        fn(...args)
      })
    }
  },
  off(name, callback){
    if(!name){
      this.events = {}
      return
    }
    if(!callback) {
      delete this.events[name]
      return
    }
    if(this.events[name]) {
      this.events[name] = this.events[name].filter(fn => fn!==callback)
    }
  }
})
const useEventBus = toRefs(eventbus)